import logging
from time import time

from channels.exceptions import ChannelFull
from channels.layers import get_channel_layer
from channels_redis.core import RedisChannelLayer as Origin
from django_redis import get_redis_connection
from redis import Redis

log = logging.getLogger(__name__)


def redis_cli():
    return get_redis_connection('default')


class RedisExtChannelLayer(Origin):
    """继承原来的RedisChannelLayer的最初目的是：
        加上一个同步发送消息的到队列的方法：send_sync。
        可以避免在一些asyncio冲突的地方出问题，这是一个保守的策略。
    """
    def send_sync(self, channel, message):
        """
        Send a message onto a (general or specific) channel.
        """
        # Typecheck
        assert isinstance(message, dict), "message is not a dict"
        assert self.valid_channel_name(channel), "Channel name not valid"
        # Make sure the message does not contain reserved keys
        assert "__asgi_channel__" not in message
        # If it's a process-local channel, strip off local part and stick full name in message
        if "!" in channel:
            message = dict(message.items())
            message["__asgi_channel__"] = channel
            channel = self.non_local_name(channel)
        # Write out message into expiring key (avoids big items in list)
        channel_key = self.prefix + channel
        # Pick a connection to the right server - consistent for specific
        # channels, random for general channels
        if "!" in channel:
            index = self.consistent_hash(channel)
        else:
            index = next(self._send_index_generator)

        log.info(f'Index: {index} and hosts: {self.hosts}')
        connection = Redis.from_url(self.hosts[index]['address'])
        # Check the length of the list before send
        # This can allow the list to leak slightly over capacity, but that's fine.
        if connection.llen(channel_key) >= self.get_capacity(channel):
            raise ChannelFull()
        # Push onto the list then set it to expire in case it's not consumed
        connection.rpush(channel_key, self.serialize(message))
        connection.expire(channel_key, int(self.expiry))


def send_user_message(user_id, message):
    cli = redis_cli()
    key = f'subscribers:user:{user_id}:bitmex'
    channels = cli.zremrangebyscore(key, 0, time() - 60)  # 移除60秒内不活跃的客户端
    channels = cli.zrange(key, 0, -1)  # 获取剩下所有客户端

    if len(channels) == 0:
            log.info('no body listening, do not push')
            return
    for channel in channels:
        try:
            channel = channel.decode('utf-8')
            channel_layer = get_channel_layer()
            channel_layer.send_sync(channel, {
                'type': 'update.message',
                'message': message
            })
        except:
            log.exception('push message error')
